/* 
 * Copyright (c)	Insighten Intelligent Equipment co.,LTD
 * 
 *  Use of this software is controlled by the terms and conditions found
 *  in the license agreement under which this software has been supplied.
 * 
 */
/** 
 * @file shrmem.c
 * @brief util for share memory
 * @author taco [tacoee@gmail.com]
 * @version 0.1
 * @date 2010-09-13
 */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <pthread.h>
#include <error.h>

#include "types.h"
#include "shrmem.h"


ShareMem *shm_create(int key, int size)
{
	ShareMem *thiz = NULL;

	thiz = calloc(sizeof(ShareMem), 1);
	
	if (thiz != NULL) {
		thiz->mid = shmget(key, size, IPC_CREAT | 0660);
		if (thiz->mid < 0) {
			thiz->mid = shmget(key, 0, 0);
		}
		if (thiz->mid < 0) {
			free(thiz);
			thiz = NULL;
		}
		pthread_mutex_init(&thiz->mutex, NULL);
		thiz->key = key;
		thiz->mem_size = size;
	}

	return thiz;
}

Ret shm_destory(ShareMem *thiz)
{
	return_val_if_fail(thiz != NULL, RET_FAIL);

	pthread_mutex_destroy(&thiz->mutex);
	free(thiz);
	thiz = NULL;

	return RET_OK;
}
Ret shm_destory_deeply(ShareMem *thiz)
{
	return_val_if_fail(thiz != NULL, RET_FAIL);

	if (shmctl(thiz->mid, IPC_RMID, NULL) < 0) {
		return RET_FAIL;
	}
	pthread_mutex_destroy(&thiz->mutex);
	free(thiz);
	thiz = NULL;

	return RET_OK;
}


Ret shm_read(ShareMem *thiz, int offset, void *buf, int length)
{
	return_val_if_fail(thiz != NULL && buf != NULL && 
			(offset+length) <= thiz->mem_size, RET_FAIL);

	pthread_mutex_lock(&thiz->mutex);
	char *src = shmat(thiz->mid, 0, 0);
	if (src != (void *)(-1)) {
		memcpy(buf, src + offset, length);
	} else {
		return RET_FAIL;
	}
	shmdt(src);
	pthread_mutex_unlock(&thiz->mutex);

	return RET_OK;
}

Ret shm_write(ShareMem *thiz, int offset, void *buf, int length)
{
	return_val_if_fail(thiz != NULL && buf != NULL &&
			(offset + length) <= thiz->mem_size, RET_FAIL);
	
	pthread_mutex_lock(&thiz->mutex);

	char *dst = shmat(thiz->mid, 0, 0);
	if (dst != (void *)(-1)) {
		memcpy(dst + offset, buf, length);
	} else {
		return RET_FAIL;
	}
	shmdt(dst);
	pthread_mutex_unlock(&thiz->mutex);
	
	return RET_OK;
}
